﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using Tesla.Core;
using Tesla.Input;
using Tesla.Windows.Util;

namespace Tesla.Windows.Input {
    /// <summary>
    /// Keyboard wrapper for Windows platform.
    /// </summary>
    public sealed class WindowsKeyboardWrapper : IKeyboardWrapper {
        private static uint _maskValue = uint.MaxValue;

        private uint _keyState0;
        private uint _keyState1;
        private uint _keyState2;
        private uint _keyState3;
        private uint _keyState4;
        private uint _keyState5;
        private uint _keyState6;
        private uint _keyState7;

        /// <summary>
        /// Get the current state of the keyboard.
        /// </summary>
        /// <exception cref="Tesla.Input.InputException">Throws an exception if there is an error in retrieving key state</exception>
        /// <returns>Keyboardstate struct</returns>
        public KeyboardState GetKeyboardState() {
            _keyState0 = _keyState1 = _keyState2 = _keyState3 = _keyState4 = _keyState5 = _keyState6 = _keyState7 = 0;

            unsafe {
                KeyByteArray keys;

                if(!NativeMethods.GetKeyboardState((byte*) &keys)) {
                    throw new TeslaException("Error getting keyboard state!");
                }

                for(int i = 0; i < 256; i++) {
                    byte key = keys.Keys[i];
                    if((key & 0x80) != 0) {
                        AddPressedKey(i);
                    }
                }
            }
            return new KeyboardState(_keyState0, _keyState1, _keyState2, _keyState3, _keyState4, _keyState5, _keyState6, _keyState7);
        }

        private void AddPressedKey(int key) {
            //Get the bit place in the state for the key
            uint place = ((uint) 1) << key;
            //Get the state grouping for the key
            int grouping = key >> 5;
            //Add the key to the proper state
            switch(grouping) {
                case 0:
                    _keyState0 |= place & _maskValue;
                    return;
                case 1:
                    _keyState1 |= place & _maskValue;
                    return;
                case 2:
                    _keyState2 |= place & _maskValue;
                    return;
                case 3:
                    _keyState3 |= place & _maskValue;
                    return;
                case 4:
                    _keyState4 |= place & _maskValue;
                    return;
                case 5:
                    _keyState5 |= place & _maskValue;
                    return;
                case 6:
                    _keyState6 |= place & _maskValue;
                    return;
                case 7:
                    _keyState7 |= place & _maskValue;
                    return;
            }
        }
    }
}
